package io.hellsinger.vortex.ui.screen.storage.create

import android.content.Context
import android.os.Bundle
import android.text.Editable
import android.view.Gravity
import android.view.View
import android.view.View.OnApplyWindowInsetsListener
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.WindowInsets
import android.widget.LinearLayout
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import io.hellsinger.filesystem.attribute.DefaultPathAttribute
import io.hellsinger.filesystem.attribute.PathType
import io.hellsinger.filesystem.linux.attribute.toLinuxEntryModeString
import io.hellsinger.filesystem.linux.path.LinuxPath
import io.hellsinger.filesystem.linux.resolve
import io.hellsinger.filesystem.linux.toIntMode
import io.hellsinger.navigation.screen.ScreenController
import io.hellsinger.theme.vortex.VortexSettings
import io.hellsinger.viewmodel.BitViewModel.UiStateUpdateCollector
import io.hellsinger.vortex.R
import io.hellsinger.vortex.bit.Bits.Companion.hasFlag
import io.hellsinger.vortex.data.model.PathItem
import io.hellsinger.vortex.di.createViewModel
import io.hellsinger.vortex.navigation.globalUiProvider
import io.hellsinger.vortex.ui.component.dp
import io.hellsinger.vortex.ui.component.drawable.RoundedCornerDrawable
import io.hellsinger.vortex.ui.component.item.field.TextFieldItemView
import io.hellsinger.vortex.ui.component.item.field.TextFieldItemView.TextWatcher
import io.hellsinger.vortex.ui.component.item.menu.MenuAction
import io.hellsinger.vortex.ui.component.item.menu.MenuActionListener
import io.hellsinger.vortex.ui.component.navigation.NavigationBarView
import io.hellsinger.vortex.ui.component.observeInsets
import io.hellsinger.vortex.ui.dsl.field
import io.hellsinger.vortex.ui.dsl.frameParams
import io.hellsinger.vortex.ui.dsl.linear
import io.hellsinger.vortex.ui.dsl.linearParams
import io.hellsinger.vortex.ui.icon.Icons
import io.hellsinger.vortex.ui.screen.storage.create.StorageCreateItemScreenController.Args
import io.hellsinger.vortex.ui.screen.storage.create.StorageCreateItemViewModel.Companion.UPDATE_INVALID_FIELD_NAME
import io.hellsinger.vortex.ui.screen.storage.create.StorageCreateItemViewModel.Companion.UPDATE_INVALID_FIELD_PATH
import io.hellsinger.vortex.ui.screen.storage.create.StorageCreateItemViewModel.Companion.UPDATE_INVALID_FIELD_PERMISSION
import io.hellsinger.vortex.ui.screen.storage.create.StorageCreateItemViewModel.Companion.UPDATE_INVALID_FIELD_TYPE
import io.hellsinger.vortex.ui.screen.storage.transaction.StorageTransactionScreenController
import io.hellsinger.vortex.ui.screen.storage.transaction.StorageTransactionScreenController.Args.Companion.LOAD_TYPE_CREATE
import io.hellsinger.vortex.ui.screen.storage.transaction.StorageTransactionScreenController.Args.Modification
import kotlin.math.roundToInt

class StorageCreateItemScreenController(
    private val context: Context,
) : ScreenController<Args>(),
    OnApplyWindowInsetsListener,
    UiStateUpdateCollector<UiState>,
    TextWatcher,
    MenuActionListener {
    private var viewModel: StorageCreateItemViewModel? = null

    private var root: LinearLayout? = null

    private var bar: NavigationBarView? = globalUiProvider(context)?.bar

    private var name: TextFieldItemView? = null
    private var type: TextFieldItemView? = null
    private var path: TextFieldItemView? = null
    private var permission: TextFieldItemView? = null

    override val usePopupMode: Boolean
        get() = false

    override fun onCreateViewImpl(context: Context): View {
        root =
            linear(context) {
                frameParams(MATCH_PARENT, MATCH_PARENT) {
                    gravity = Gravity.BOTTOM
                }
                orientation = LinearLayout.VERTICAL
                background =
                    RoundedCornerDrawable(
                        color = VortexSettings.colors { key_storage_create_item_background_color },
                    )
                observeInsets(this@StorageCreateItemScreenController)
                updatePadding(left = 8.dp, right = 8.dp)

                name =
                    field {
                        id = R.id.file_manager_create_name_field
                        hint = "Name"
                        setFieldTextColor(VortexSettings.colors { key_storage_create_item_field_text_color })
                        setHintTextColor(VortexSettings.colors { key_storage_create_item_field_hint_color })
                        setFieldLineColor(VortexSettings.colors { key_storage_create_item_field_line_color })
                        setFieldCursorColor(VortexSettings.colors { key_storage_create_item_field_cursor_color })
                        linearParams(MATCH_PARENT, WRAP_CONTENT)
                        updatePadding(top = 8.dp, bottom = 8.dp)
                    }
                path =
                    field {
                        id = R.id.file_manager_create_path_field
                        hint = "Path"
                        setFieldTextColor(VortexSettings.colors { key_storage_create_item_field_text_color })
                        setHintTextColor(VortexSettings.colors { key_storage_create_item_field_hint_color })
                        setFieldLineColor(VortexSettings.colors { key_storage_create_item_field_line_color })
                        setFieldCursorColor(VortexSettings.colors { key_storage_create_item_field_cursor_color })
                        linearParams(MATCH_PARENT, WRAP_CONTENT)
                    }
                type =
                    field {
                        id = R.id.file_manager_create_type_field
                        hint = "Type (e.g. Directory, Link, File by default)"
                        setFieldTextColor(VortexSettings.colors { key_storage_create_item_field_text_color })
                        setHintTextColor(VortexSettings.colors { key_storage_create_item_field_hint_color })
                        setFieldLineColor(VortexSettings.colors { key_storage_create_item_field_line_color })
                        setFieldCursorColor(VortexSettings.colors { key_storage_create_item_field_cursor_color })
                        linearParams(MATCH_PARENT, WRAP_CONTENT)
                    }
                permission =
                    field {
                        id = R.id.file_manager_create_permission_filed
                        hint = "Permission (rwxrwxrwx or just RWX)"
                        setFieldTextColor(VortexSettings.colors { key_storage_create_item_field_text_color })
                        setHintTextColor(VortexSettings.colors { key_storage_create_item_field_hint_color })
                        setFieldLineColor(VortexSettings.colors { key_storage_create_item_field_line_color })
                        setFieldCursorColor(VortexSettings.colors { key_storage_create_item_field_cursor_color })
                        linearParams(MATCH_PARENT, WRAP_CONTENT)
                    }
            }

        return root!!
    }

    override fun onApplyWindowInsets(
        v: View,
        insets: WindowInsets,
    ): WindowInsets {
        val compat = WindowInsetsCompat.toWindowInsetsCompat(insets)
        val statusBar = compat.getInsets(WindowInsetsCompat.Type.statusBars())
        val navigationBar = compat.getInsets(WindowInsetsCompat.Type.navigationBars())
        val ime = compat.getInsets(WindowInsetsCompat.Type.ime())

        val barHeight = bar?.height ?: 0
        val bottomPadding = if (ime.bottom > 0) ime.bottom else barHeight

        root?.updatePadding(
            top = statusBar.top,
            bottom = bottomPadding + context.dp(4F).roundToInt(),
        )
        return insets
    }

    override fun afterTextChanged(
        view: TextFieldItemView,
        sequence: Editable,
    ) {
        when (view.id) {
            R.id.file_manager_create_name_field -> viewModel?.updateName(sequence.toString())
            R.id.file_manager_create_path_field -> viewModel?.updatePath(sequence.toString())
            R.id.file_manager_create_type_field -> viewModel?.updateType(sequence.toString())
            R.id.file_manager_create_permission_filed -> viewModel?.updatePermission(sequence.toString())
        }
    }

    override fun beforeTextChanged(
        view: TextFieldItemView,
        sequence: CharSequence,
        start: Int,
        count: Int,
        after: Int,
    ) = Unit

    override fun onTextChanged(
        view: TextFieldItemView,
        sequence: CharSequence,
        start: Int,
        before: Int,
        count: Int,
    ) = Unit

    override fun onBackActivatedImpl(): Boolean = false

    override fun onPrepareImpl() {
        if (viewModel == null) {
            viewModel = context.createViewModel()
        }

        when (args) {
            is Args.ParentPath -> {
                val parent = (args as Args.ParentPath).item.path.toString()
                path?.text = parent
                viewModel?.updatePath(parent)
            }
        }

        bar?.title = "Create new storage item"
        bar?.replaceItems(
            listOf(
                MenuAction(
                    R.id.file_manager_create_proceed,
                    "Proceed",
                    Icons.Rounded.ArrowRight,
                ),
            ),
        )
        bar?.registerListener(this)
        viewModel?.collectUiState(this)

        name?.addTextWatcher(this@StorageCreateItemScreenController)
        path?.addTextWatcher(this@StorageCreateItemScreenController)
        type?.addTextWatcher(this@StorageCreateItemScreenController)
    }

    override fun onMenuActionCall(id: Int): Boolean {
        when (id) {
            R.id.file_manager_create_proceed -> {
                val name = name?.text ?: return true
                val path = path?.text ?: return true
                val type =
                    when (type?.text) {
                        "Dir" -> PathType.Directory
                        "Directory" -> PathType.Directory
                        "File" -> PathType.File
                        else -> return true
                    }
                val permission = permission?.text ?: return true
                val destPath = LinuxPath(path.encodeToByteArray()).resolve(name)
                val attrs =
                    DefaultPathAttribute(
                        type = type,
                        permission = permission.toIntMode().toLinuxEntryModeString(),
                        size = 0L,
                    )
                val dest = PathItem(destPath, attrs)
                router?.navigate(
                    StorageTransactionScreenController(context),
                    Modification(listOf(dest), LOAD_TYPE_CREATE),
                )
                return true
            }
        }
        return false
    }

    override suspend fun emit(
        event: Int,
        state: UiState,
    ) {
        if (event hasFlag UPDATE_INVALID_FIELD_NAME) {
            name?.error =
                when {
                    event hasFlag StorageCreateItemViewModel.REASON_INVALID_SYMBOL -> "Field contains invalid symbol"
                    event hasFlag StorageCreateItemViewModel.REASON_PART_IS_EMPTY -> "Field can not be empty"
                    event hasFlag StorageCreateItemViewModel.REASON_PATH_MUST_STARTS_FROM_SLASH -> "Filed must start from '/'"
                    else -> ""
                }
        }
        if (event hasFlag UPDATE_INVALID_FIELD_PATH) {
            path?.error =
                when {
                    event hasFlag StorageCreateItemViewModel.REASON_INVALID_SYMBOL -> "Field contains invalid symbol"
                    event hasFlag StorageCreateItemViewModel.REASON_PART_IS_EMPTY -> "Field can not be empty"
                    event hasFlag StorageCreateItemViewModel.REASON_PATH_MUST_STARTS_FROM_SLASH -> "Filed must start from '/'"
                    else -> ""
                }
        }
        if (event hasFlag UPDATE_INVALID_FIELD_TYPE) {
            type?.error =
                when {
                    event hasFlag StorageCreateItemViewModel.REASON_INVALID_SYMBOL -> "Field contains invalid symbol"
                    event hasFlag StorageCreateItemViewModel.REASON_PART_IS_EMPTY -> "Field can not be empty"
                    event hasFlag StorageCreateItemViewModel.REASON_PATH_MUST_STARTS_FROM_SLASH -> "Filed must start from '/'"
                    else -> ""
                }
        }
        if (event hasFlag UPDATE_INVALID_FIELD_PERMISSION) {
            permission?.error =
                when {
                    event hasFlag StorageCreateItemViewModel.REASON_INVALID_SYMBOL -> "Field contains invalid symbol"
                    event hasFlag StorageCreateItemViewModel.REASON_PART_IS_EMPTY -> "Field can not be empty"
                    event hasFlag StorageCreateItemViewModel.REASON_PATH_MUST_STARTS_FROM_SLASH -> "Filed must start from '/'"
                    else -> ""
                }
        }
    }

    override fun onFocusImpl() {
        name?.requestFocus()
    }

    override fun onHideImpl() {
        bar?.unregisterListener(this)
        viewModel?.cancelCollectUiState()
    }

    override fun onDestroyImpl() {
        viewModel?.onDestroy()
        viewModel = null
        root?.removeAllViews()
        root = null
    }

    interface Args {
        class ParentPath(
            val item: PathItem,
        ) : Args
    }

    override fun onSaveImpl(
        buffer: Bundle,
        prefix: String,
    ): Boolean = false

    override fun onRestoreImpl(
        buffer: Bundle,
        prefix: String,
    ): Boolean = false
}
